﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ARR.Entities;
using System.IO;
using System.Configuration;
using System.Data;
using DDF.Entity;
using System.Reflection;
using ARR.Shared;
using OfficeOpenXml;

namespace ARR.Services.Domain.Importers
{
    public static class ImporterHelper
    {
        public static Dictionary<string, string> GetFieldsFromFixedColumnLine(string line, List<ColumnFormat> columns)
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();
            int cursor = 0;

            try
            {
                foreach (ColumnFormat col in columns.OrderBy(c => c.ColumnIndex))
                {
                    if (!col.IsLastColumn)
                        dic.Add(col.ColumnName, line.Substring(cursor, col.ColumnLength).Trim());
                    else
                        dic.Add(col.ColumnName, line.Substring(cursor).Trim());

                    cursor += col.ColumnLength;
                }
            }
            catch
            {
                return null;
            }

            return dic;
        }

        public static string GetHistoryFilesPath()
        {
            return Path.Combine(ConfigurationManager.AppSettings["ImportersPath"], Constants.ImportSettings.HistoryFolder);
        }

        public static string GetSpacesFilesPath(Country country, string rangeReviewTitle)
        {
            string sourceDirectoryPath = Path.Combine(ConfigurationManager.AppSettings["ImportersPath"], country.Code, rangeReviewTitle, Constants.ImportSettings.SpacesFolder);

            return sourceDirectoryPath;
        }

        public static string GetSalesFilesPath(Country country, string rangeReviewTitle)
        {
            string sourceDirectoryPath = Path.Combine(ConfigurationManager.AppSettings["ImportersPath"], country.Code, rangeReviewTitle, Constants.ImportSettings.SalesFolder);

            return sourceDirectoryPath;
        }

        public static string GetSalesResultsFilesPath(Country country, string rangeReviewTitle)
        {
            string sourceDirectoryPath = Path.Combine(ConfigurationManager.AppSettings["ImportersPath"], country.Code, rangeReviewTitle, Constants.ImportSettings.SalesFolder, Constants.ImportSettings.ResultsFilesFolder);

            return sourceDirectoryPath;
        }

        public static string GetArticleMasterFilePath(Country country, string rangeReviewTitle)
        {
            string sourceDirectoryPath = Path.Combine(ConfigurationManager.AppSettings["ImportersPath"], country.Code, rangeReviewTitle, Constants.ImportSettings.SalesFolder);

            if (country.IsArticleMasterSeparateFile)
                sourceDirectoryPath = Path.Combine(ConfigurationManager.AppSettings["ImportersPath"], country.Code, rangeReviewTitle, Constants.ImportSettings.ArticleMasterFolder);

            return sourceDirectoryPath;
        }

        public static string GetArticleMasterResultsFilePath(Country country, string rangeReviewTitle)
        {
            string sourceDirectoryPath = Path.Combine(ConfigurationManager.AppSettings["ImportersPath"], country.Code, rangeReviewTitle, Constants.ImportSettings.SalesFolder, Constants.ImportSettings.ResultsFilesFolder);

            if (country.IsArticleMasterSeparateFile)
                sourceDirectoryPath = Path.Combine(ConfigurationManager.AppSettings["ImportersPath"], country.Code, rangeReviewTitle, Constants.ImportSettings.ArticleMasterFolder, Constants.ImportSettings.ResultsFilesFolder);

            return sourceDirectoryPath;
        }

        public static string GetStoreMasterFilePath(Country country, string rangeReviewTitle)
        {
            string sourceDirectoryPath = Path.Combine(ConfigurationManager.AppSettings["ImportersPath"], country.Code, rangeReviewTitle, Constants.ImportSettings.SalesFolder);

            if (country.IsStoreMasterSeparateFile)
                sourceDirectoryPath = Path.Combine(ConfigurationManager.AppSettings["ImportersPath"], country.Code, rangeReviewTitle, Constants.ImportSettings.StoreMasterFolder);

            return sourceDirectoryPath;
        }

        public static string GetInventoryMasterFilePath(Country country, string rangeReviewTitle)
        {
            string sourceDirectoryPath = Path.Combine(ConfigurationManager.AppSettings["ImportersPath"], country.Code, rangeReviewTitle, Constants.ImportSettings.InventoryFolder);


            return sourceDirectoryPath;
        }

        public static string GetPIDifferencesFilePath(Country country, string rangeReviewTitle)
        {
            string sourceDirectoryPath = Path.Combine(ConfigurationManager.AppSettings["ImportersPath"], country.Code, rangeReviewTitle, Constants.ImportSettings.PIDifferencesFolder);


            return sourceDirectoryPath;
        }

        public static string GetStoreMasterResultsFilePath(Country country, string rangeReviewTitle)
        {
            string sourceDirectoryPath = Path.Combine(ConfigurationManager.AppSettings["ImportersPath"], country.Code, rangeReviewTitle, Constants.ImportSettings.SalesFolder, Constants.ImportSettings.ResultsFilesFolder);

            if (country.IsStoreMasterSeparateFile)
                sourceDirectoryPath = Path.Combine(ConfigurationManager.AppSettings["ImportersPath"], country.Code, rangeReviewTitle, Constants.ImportSettings.StoreMasterFolder, Constants.ImportSettings.ResultsFilesFolder);

            return sourceDirectoryPath;
        }

        public static DataTable CreateDataTableFromGateway<T>() where T : EntityStateTracker
        {
            DataTable dt = new DataTable();

            Type type = typeof(T);

            foreach (PropertyInfo prop in type.GetProperties())
            {
                if (prop.DeclaringType == type)
                {
                    if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
                    {
                        // Es nullable y DataTable no soporta nullables.
                        dt.Columns.Add(new DataColumn(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType)));
                    }
                    else
                    {
                        dt.Columns.Add(new DataColumn(prop.Name, prop.PropertyType));
                    }
                }
            }

            return dt;
        }

        public static void MoveImportedFilesAndWriteLog(Country country, string sourceDirectoryPath)
        {
            //Muevo los archivos a la carpeta Old            
            DirectoryInfo di = new DirectoryInfo(sourceDirectoryPath);

            foreach (var fileInfo in di.GetFiles())
            {
                string oldFolder = Path.Combine(fileInfo.Directory.FullName, "Old");
                string newFile = Path.Combine(oldFolder, fileInfo.Name);

                if (System.IO.File.Exists(newFile))
                {
                    //fileInfo.Delete();
                }
                else
                {
                    //fileInfo.MoveTo(newFile);
                }

                //TODO: Agregar un registro a alguna tabla de logging, informando la importación realizada.
            }
        }

        public static void ConvertToDelimitedFile(string fileName, int[] delimiterPositions, string outputFileName)
        {
            string line;
            char[] array;

            using (StreamWriter sw = new StreamWriter(outputFileName))
            {
                using (StreamReader sr = new StreamReader(fileName, System.Text.Encoding.Default, true))
                {
                    while (!sr.EndOfStream)
                    {
                        line = sr.ReadLine();

                        if (!line.StartsWith("Store Prov ") && !line.StartsWith("-----") && !string.IsNullOrWhiteSpace(line))
                        {
                            array = line.ToArray();

                            foreach (int i in delimiterPositions)
                            {
                                array[i] = '|';
                            }

                            sw.WriteLine(array);
                        }
                        else
                        {
                            sw.WriteLine(line);
                        }
                    }
                }
            }
        }

        public static string GetErrorLocation(string fileName, int? rowNumber)
        {
            string location = "Error Location could not be determined.";

            if (fileName != null)
            {
                if (rowNumber != null)
                {
                    location = string.Format(Errors.ImporterErrorLocationFileAndLineNumber, fileName, rowNumber);
                }
                else
                {
                    location = string.Format(Errors.ImporterErrorLocationFile, fileName);
                }
            }

            return location;
        }

        public static IList<ImporterResult> ExcelImporterStep1Validations(string correctHeader, string headerRange, string[] files)
        {
            IList<ImporterResult> importerResults = new List<ImporterResult>();

            string fileName = null;
            int? rowNumber = null;
            int errorCount = 0;
            try
            {
                //Check Prerequisites
                //1. Chequeo que esté el archivo
                if (files.Length == 0)
                {
                    errorCount++;
                    importerResults.Add(new ImporterResult
                    {
                        Category = ResultCategory.PreRequisites,
                        Description = Errors.NoFilesToImport,
                        ErrorType = ErrorType.Error,
                        Id = errorCount
                    });
                }
                else
                {

                    importerResults.Add(new ImporterResult
                    {
                        ErrorType = ErrorType.Information,
                        Category = ResultCategory.PreRequisites,
                        Description = Messages.ChequeoArchivosCorrecto
                    });

                    //2. Chequeo que los archivos sean xls o xlsx
                    if (!files.Any(x => x.EndsWith("xlsx")))
                    {
                        errorCount++;
                        importerResults.Add(new ImporterResult
                        {
                            Category = ResultCategory.PreRequisites,
                            Description = Errors.ImporterErrorExcel2007Format,
                            ErrorType = ErrorType.Error,
                            Id = errorCount
                        });
                    }
                    else
                    {
                        foreach (string file in files.Where(x => x.EndsWith("xlsx")))
                        {
                            fileName = file;
                            ExcelPackage excel = new ExcelPackage(new FileInfo(file));
                            if (excel != null && excel.Workbook != null)
                            {
                                //Chequeo el formato
                                bool allSheetsOK = true;

                                foreach (var sheet in excel.Workbook.Worksheets)
                                {
                                    string header = string.Empty;

                                    foreach (var cell in sheet.Cells[headerRange]) //Chequeo la primer hoja del excel
                                    {
                                        if (cell.Value != null)
                                        {
                                            header += "|" + cell.Value.ToString().Trim().ToLower();
                                        }
                                    }

                                    if (!string.IsNullOrWhiteSpace(header) && header != correctHeader)
                                    {
                                        allSheetsOK = false;
                                        errorCount++;
                                        importerResults.Add(new ImporterResult
                                        {
                                            Category = ResultCategory.PreRequisites,
                                            Description = "La planilla debe comenzar en la primer hoja del Excel en la celda A2 y tener las siguientes columnas: " + correctHeader,
                                            Location = string.Format("Archivo: {0} - Hoja: {1}", fileName, sheet.Name),
                                            ErrorType = ErrorType.Error,
                                            Id = errorCount
                                        });
                                    }
                                }

                                if (allSheetsOK)
                                {
                                    importerResults.Add(new ImporterResult
                                    {
                                        ErrorType = ErrorType.Information,
                                        Category = ResultCategory.PreRequisites,
                                        Description = string.Format(Messages.ChequeoCabeceraCorrecto, fileName)
                                    });
                                }
                            }
                        }
                    }

                }
            }
            catch (Exception ex)
            {
                errorCount++;
                importerResults.Add(new ImporterResult
                {
                    Category = ResultCategory.PreRequisites,
                    Location = ImporterHelper.GetErrorLocation(fileName, rowNumber),
                    Description = ex.Message,
                    ErrorType = ErrorType.Error,
                    Id = errorCount
                });
            }

            return importerResults;
        }

        private static List<Category> categories;
        private static List<CategoryMatch> categoryMatches;
        public static Category GetCategoryByCodeCheckingMatches(string categoryCode, int countryId)
        {
            if (categories == null)
                categories = CategoriesDomain.GetAll();

            if (categoryMatches == null)
                categoryMatches = CategoriesDomain.GetCategoryMatches(countryId);

            if (categories.Where(x => x.Code == categoryCode).Any())
            {
                return categories.Single(x => x.Code == categoryCode);
            }
            else
            {
                var match = categoryMatches.SingleOrDefault(x => x.Name == categoryCode);

                if (match != null)
                    return categories.SingleOrDefault(x => x.Id == match.CategoryId);
            }


            return null;
        }
    }

}
